﻿/*
* Copyright 2009-2010 AKABANA.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 
* either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/
using System;
using System.Globalization;
using System.Reflection;

namespace Akabana.Amf.Util
{

    public static class MethodInfoUtil
    {
#if !SILVERLIGHT 
        private static Binder binder = new MethodBinder();

        public static object Invoke(object instance, MethodBase methodInfo, object[] args)
        {
            object result = methodInfo.Invoke(
                        instance,
                        BindingFlags.Public | BindingFlags.Instance,
                        binder,
                        args,
                        null
                    );
            return result;
        }

        public static MethodInfo GetMethod(Type type, string methodName, Type[] paramTypes)
        {
            try
            {
                var result = type.GetMethod(
                        methodName,
                        BindingFlags.Public | BindingFlags.Instance,
                        binder,
                        paramTypes,
                        null
                    );
                return result;
            }
            catch (System.Exception e)
            {
                throw new System.Exception(type.FullName + "#" + methodName + "(" + paramTypes + ")", e);
            }
        }
#endif
    }

#if !SILVERLIGHT 
    class MethodBinder : Binder
    {

        public override PropertyInfo SelectProperty(BindingFlags bindingAttr, PropertyInfo[] match, Type returnType, Type[] indexes, ParameterModifier[] modifiers)
        {
            throw new System.Exception("no implementation");
        }

        public override FieldInfo BindToField(BindingFlags bindingAttr, FieldInfo[] match, object value, CultureInfo culture)
        {
            throw new System.Exception("no implementation");
        }

        public override MethodBase BindToMethod(BindingFlags bindingAttr, MethodBase[] match, ref object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] names, out object state)
        {
            throw new System.Exception("no implementation");
        }

        public override void ReorderArgumentArray(ref object[] args, object state)
        {
            throw new System.Exception("no implementation");
        }

        public override object ChangeType( object value, Type changeType, CultureInfo culture)
        {
            return TypeUtil.ChangeType(value,changeType,culture);
        }

        public override MethodBase SelectMethod( BindingFlags bindingAttr, MethodBase[] match, Type[] types, ParameterModifier[] modifiers )
        {
            if (match == null)
            {
                return null;
            }
            for (int i = 0; i < match.Length; i++)
            {
                var parameters = match[i].GetParameters();

                if (types.Length != parameters.Length)
                {
                    continue;
                }

                int count = 0;
                for (int j = 0; j < types.Length; j++)
                {
                    if (TypeUtil.CanConvertFrom(types[j], parameters[j].ParameterType))
                    {
                        count += 1;
                    }
                    else
                    {
                        break;
                    }
                }
                
                if (count == types.Length)
                {
                    return match[i];
                }
            }
            return null;
        }
    }
#endif
}
